package com.ics.atable.chat.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.ics.atable.chat.model.entity.DbConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态数据源管理器
 * 
 * 负责管理多个数据源的创建、切换和销毁
 * 使用Druid连接池来管理数据库连接
 * 
 * @author Chawu
 */
@Slf4j
@Component
public class DynamicDataSourceManager {
    
    /**
     * 存储所有数据源的Map
     * key: 数据源名称
     * value: DruidDataSource对象
     */
    private final Map<String, DruidDataSource> dataSourceMap = new ConcurrentHashMap<>();
    
    /**
     * 存储所有JdbcTemplate的Map
     * key: 数据源名称
     * value: JdbcTemplate对象
     */
    private final Map<String, JdbcTemplate> jdbcTemplateMap = new ConcurrentHashMap<>();
    
    /**
     * 当前使用的数据源名称
     * 使用ThreadLocal确保线程安全
     */
    private static final ThreadLocal<String> currentDataSourceName = new ThreadLocal<>();
    
    /**
     * 创建数据源
     * 
     * @param dbConfig 数据库配置信息
     * @return 创建的数据源对象
     */
    public DruidDataSource createDataSource(DbConfig dbConfig) {
        try {
            // 创建Druid数据源
            DruidDataSource dataSource = new DruidDataSource();
            
            // 设置基本连接信息
            dataSource.setUrl(dbConfig.getJdbcUrl());
            dataSource.setUsername(dbConfig.getUsername());
            dataSource.setPassword(dbConfig.getPassword());
            dataSource.setDriverClassName(dbConfig.getDriverClass());
            
            // 设置连接池配置
            dataSource.setInitialSize(2);           // 初始连接数
            dataSource.setMinIdle(2);               // 最小空闲连接数
            dataSource.setMaxActive(20);            // 最大连接数
            dataSource.setMaxWait(60000);           // 获取连接最大等待时间（毫秒）
            dataSource.setTimeBetweenEvictionRunsMillis(60000);  // 检测空闲连接的时间间隔
            dataSource.setMinEvictableIdleTimeMillis(300000);    // 连接在池中最小生存时间
            dataSource.setValidationQuery("SELECT 1");          // 验证查询
            dataSource.setTestWhileIdle(true);      // 空闲时测试连接
            dataSource.setTestOnBorrow(false);      // 获取连接时不测试
            dataSource.setTestOnReturn(false);      // 归还连接时不测试
            
            // 设置连接泄漏检测
            dataSource.setRemoveAbandoned(true);    // 开启连接泄漏检测
            dataSource.setRemoveAbandonedTimeout(1800); // 连接泄漏超时时间（秒）
            dataSource.setLogAbandoned(true);       // 记录连接泄漏日志
            
            // 初始化数据源
            dataSource.init();
            
            log.info("成功创建数据源: {}", dbConfig.getName());
            return dataSource;
            
        } catch (SQLException e) {
            log.error("创建数据源失败: {}, 错误信息: {}", dbConfig.getName(), e.getMessage(), e);
            throw new RuntimeException("创建数据源失败: " + dbConfig.getName(), e);
        }
    }
    
    /**
     * 添加数据源
     * 
     * @param dbConfig 数据库配置信息
     */
    public void addDataSource(DbConfig dbConfig) {
        String name = dbConfig.getName();
        
        // 如果数据源已存在，先关闭旧的数据源
        if (dataSourceMap.containsKey(name)) {
            removeDataSource(name);
        }
        
        // 创建新的数据源
        DruidDataSource dataSource = createDataSource(dbConfig);
        dataSourceMap.put(name, dataSource);
        
        // 创建对应的JdbcTemplate
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplateMap.put(name, jdbcTemplate);
        
        log.info("成功添加数据源: {}", name);
    }
    
    /**
     * 移除数据源
     * 
     * @param name 数据源名称
     */
    public void removeDataSource(String name) {
        // 关闭数据源
        DruidDataSource dataSource = dataSourceMap.remove(name);
        if (dataSource != null) {
            try {
                dataSource.close();
                log.info("成功关闭数据源: {}", name);
            } catch (Exception e) {
                log.error("关闭数据源失败: {}, 错误信息: {}", name, e.getMessage(), e);
            }
        }
        
        // 移除JdbcTemplate
        jdbcTemplateMap.remove(name);
        
        log.info("成功移除数据源: {}", name);
    }
    
    /**
     * 获取数据源
     * 
     * @param name 数据源名称
     * @return 数据源对象
     */
    public DataSource getDataSource(String name) {
        return dataSourceMap.get(name);
    }
    
    /**
     * 获取JdbcTemplate
     * 
     * @param name 数据源名称
     * @return JdbcTemplate对象
     */
    public JdbcTemplate getJdbcTemplate(String name) {
        return jdbcTemplateMap.get(name);
    }
    
    /**
     * 设置当前数据源
     * 
     * @param name 数据源名称
     */
    public void setCurrentDataSource(String name) {
        currentDataSourceName.set(name);
    }
    
    /**
     * 获取当前数据源名称
     * 
     * @return 当前数据源名称
     */
    public String getCurrentDataSource() {
        return currentDataSourceName.get();
    }
    
    /**
     * 清除当前数据源设置
     */
    public void clearCurrentDataSource() {
        currentDataSourceName.remove();
    }
    
    /**
     * 检查数据源是否存在
     * 
     * @param name 数据源名称
     * @return 是否存在
     */
    public boolean containsDataSource(String name) {
        return dataSourceMap.containsKey(name);
    }
    
    /**
     * 获取所有数据源名称
     * 
     * @return 数据源名称列表
     */
    public List<String> getAllDataSourceNames() {
        return List.copyOf(dataSourceMap.keySet());
    }
    
    /**
     * 测试数据源连接
     * 
     * @param name 数据源名称
     * @return 连接是否成功
     */
    public boolean testConnection(String name) {
        try {
            DruidDataSource dataSource = dataSourceMap.get(name);
            if (dataSource == null) {
                return false;
            }
            
            // 尝试获取连接来测试
            dataSource.getConnection().close();
            return true;
            
        } catch (SQLException e) {
            log.error("测试数据源连接失败: {}, 错误信息: {}", name, e.getMessage());
            return false;
        }
    }
    
    /**
     * 关闭所有数据源
     * 在应用关闭时调用
     */
    public void closeAllDataSources() {
        log.info("开始关闭所有数据源...");
        
        for (Map.Entry<String, DruidDataSource> entry : dataSourceMap.entrySet()) {
            try {
                entry.getValue().close();
                log.info("成功关闭数据源: {}", entry.getKey());
            } catch (Exception e) {
                log.error("关闭数据源失败: {}, 错误信息: {}", entry.getKey(), e.getMessage(), e);
            }
        }
        
        dataSourceMap.clear();
        jdbcTemplateMap.clear();
        log.info("所有数据源已关闭");
    }
}
